package com.codeanalysissys.backend.entity.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.codeanalysissys.backend.cpp.CppASTBuilder;
import com.codeanalysissys.backend.cpp.CppCFGBuilder;
import com.codeanalysissys.backend.cpp.CppDDGBuilder;
import com.codeanalysissys.backend.golang.GoASTBuilder;
import com.codeanalysissys.backend.golang.GoCDGBuilder;
import com.codeanalysissys.backend.golang.GoCFGBuilder;
import com.codeanalysissys.backend.golang.GoDDGBuilder;
import com.codeanalysissys.backend.graphs.ast.ASEdge;
import com.codeanalysissys.backend.graphs.ast.ASNode;
import com.codeanalysissys.backend.graphs.ast.AbstractSyntaxTree;
import com.codeanalysissys.backend.graphs.cfg.CFEdge;
import com.codeanalysissys.backend.graphs.cfg.CFNode;
import com.codeanalysissys.backend.graphs.cfg.ControlFlowGraph;
import com.codeanalysissys.backend.graphs.pdg.*;
import com.codeanalysissys.backend.java.JavaASTBuilder;
import com.codeanalysissys.backend.java.JavaCDGBuilder;
import com.codeanalysissys.backend.java.JavaCFGBuilder;
import com.codeanalysissys.backend.java.JavaDDGBuilder;
import com.codeanalysissys.backend.javascript.JavaScriptASTBuilder;
import com.codeanalysissys.backend.javascript.JavaScriptCDGBuilder;
import com.codeanalysissys.backend.javascript.JavaScriptCFGBuilder;
import com.codeanalysissys.backend.javascript.JavaScriptDDGBuilder;
import com.codeanalysissys.backend.python.PythonASTBuilder;
import com.codeanalysissys.backend.python.PythonCDGBuilder;
import com.codeanalysissys.backend.python.PythonCFGBuilder;
import com.codeanalysissys.backend.python.PythonDDGBuilder;
import com.codeanalysissys.backend.ruby.RubyASTBuilder;
import com.codeanalysissys.backend.ruby.RubyCDGBuilder;
import com.codeanalysissys.backend.ruby.RubyCFGBuilder;
import com.codeanalysissys.backend.ruby.RubyDDGBuilder;
import ghaffarian.graphs.Edge;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.*;

@Slf4j
public class JSONLAnalysisTask implements Runnable {
    private String line;
    private Integer lineNum;
    private String fileName;
    private Map<String, Set<String>> map1;
    private Map<String, Set<String>> map2;
    private Map<String, Set<String>> map3;
    private Map<String, Set<String>> map4;
    private final BufferedWriter bufferedWriter;

    public JSONLAnalysisTask(String line, Integer lineNum, String fileName, BufferedWriter bufferedWriter) {
        this.line = line;
        this.lineNum = lineNum;
        this.fileName = fileName;
        this.map1 = new HashMap<>(256);
        this.map2 = new HashMap<>(256);
        this.map3 = new HashMap<>(256);
        this.map4 = new HashMap<>(256);
        this.bufferedWriter = bufferedWriter;
    }

    @Override
    public void run() {
        DecimalFormat formatter = new DecimalFormat("##.##%");

        // 提取行内信息，包括路径、类名和语言
        JSONObject jsonObj = JSON.parseObject(line);
        String path = jsonObj.getString("path");
        String className = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
        String selectLanguage = jsonObj.getString("language");

        try {
            // 根据语言选择对应的解析器
            switch (selectLanguage) {
                case "java" -> {
                    log.info("You selected Java programming language.");
                    // 执行与 Java 相关的代码,首先为 csn 代码加上对应的类名
                    String code = "class " + className + " {\n" + jsonObj.getString("code") + "\n}";
                    try {
                        try {
                            // 解析 CFG
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlFlowGraph cfg = JavaCFGBuilder.build(codeStream);
                            // 打包 CFG
                            packCFG(map1, jsonObj, cfg);
                        } catch (Throwable ex) {
                            log.error("java文件CFG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            // 解析 DDG
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            DataDependenceGraph ddg = JavaDDGBuilder.build(codeStream);
                            // 打包 DDG
                            packDDG(map3, jsonObj, ddg);
                        } catch (Throwable ex) {
                            log.error("java文件DDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            // 解析 CDG
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlDependenceGraph cdg = JavaCDGBuilder.build(codeStream);
                            // 打包 CDG
                            packCDG(map2, jsonObj, cdg);
                        } catch (Throwable ex) {
                            log.error("java文件CDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            AbstractSyntaxTree ast = JavaASTBuilder.build(codeStream);
                            // 打包AST
                            packAST(map4, jsonObj, ast);
                        } catch (Throwable ex) {
                            log.error("java文件AST解析异常：" + fileName + "行数：" + lineNum);
                        }
                        bufferedWriter.write(jsonObj.toJSONString());
                        bufferedWriter.newLine();
                        log.info("第" + lineNum + "行处理完毕!");
                    } catch (Throwable ex) {
                        log.error(ex.getMessage());
                    } finally {
                        map1.clear();
                        map2.clear();
                        map3.clear();
                        map4.clear();
//                        log.info("文件" + fileName + ":" + formatter.format((double) lineNum / 30000));
                    }
                }

                case "python" -> {
                    log.info("You selected Python programming language.");
                    // 执行与Python相关的代码,首先为csn代码加上对应的类名
                    String code = jsonObj.getString("code");
                    try {
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlFlowGraph cfg = PythonCFGBuilder.build(codeStream);
                            // 打包CFG
                            packCFG(map1, jsonObj, cfg);
                        } catch (Throwable ex) {
                            log.error("python文件CFG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes2 = code.getBytes();
                            InputStream codeStream2 = new ByteArrayInputStream(bytes2);
                            DataDependenceGraph ddg = PythonDDGBuilder.build(codeStream2);
                            // 打包DDG
                            packDDG(map3, jsonObj, ddg);
                        } catch (Throwable ex) {
                            log.error("python文件DDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlDependenceGraph cdg = PythonCDGBuilder.build(codeStream);
                            // 打包CDG
                            packCDG(map2, jsonObj, cdg);
                        } catch (Throwable ex) {
                            log.error("python文件CDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            AbstractSyntaxTree ast = PythonASTBuilder.build(codeStream);
                            // 打包AST
                            packAST(map4, jsonObj, ast);
                        } catch (Throwable ex) {
                            log.error("python文件AST解析异常：" + fileName + "行数：" + lineNum);
                        }
                        bufferedWriter.write(jsonObj.toJSONString());
                        bufferedWriter.newLine();
                        log.error("第" + lineNum + "行处理完毕!");
                    } catch (Throwable ex) {
                        log.error("文件：" + fileName + "行数：" + lineNum);
                    } finally {
                        map1.clear();
                        map2.clear();
                        map3.clear();
                        map4.clear();
                        log.error("文件" + fileName + ":" + formatter.format((double) lineNum / 30000));
                    }
                }

                case "go" -> {
                    log.info("You selected Go programming language.");
                    // 执行与Java相关的代码,首先为csn代码加上对应的类名
                    String code = jsonObj.getString("code");
                    try {
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlFlowGraph cfg = GoCFGBuilder.build(codeStream);
                            // 打包CFG
                            packCFG(map1, jsonObj, cfg);
                        } catch (Throwable ex) {
                            log.error("go文件CFG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes2 = code.getBytes();
                            InputStream codeStream2 = new ByteArrayInputStream(bytes2);
                            DataDependenceGraph ddg = GoDDGBuilder.build(codeStream2);
                            // 打包DDG
                            packDDG(map3, jsonObj, ddg);
                        } catch (Throwable ex) {
                            log.error("go文件DDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlDependenceGraph cdg = GoCDGBuilder.build(codeStream);
                            // 打包CDG
                            packCDG(map2, jsonObj, cdg);
                        } catch (Throwable ex) {
                            log.error("go文件CDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            AbstractSyntaxTree ast = GoASTBuilder.build(codeStream);
                            // 打包AST
                            packAST(map4, jsonObj, ast);
                        } catch (Throwable ex) {
                            log.error("go文件AST解析异常：" + fileName + "行数：" + lineNum);
                        }
                        bufferedWriter.write(jsonObj.toJSONString());
                        bufferedWriter.newLine();
                        log.error("第" + lineNum + "行处理完毕!");
                    } catch (Throwable ex) {
                        log.error("文件：" + fileName + "行数：" + lineNum);
                    } finally {
                        map1.clear();
                        map2.clear();
                        map3.clear();
                        map4.clear();
                        log.error("文件" + fileName + ":" + formatter.format((double) lineNum / 30000));
                    }
                }

                case "ruby" -> {
                    log.info("You selected Ruby programming language.");
                    // 执行与Java相关的代码,首先为csn代码加上对应的类名
                    String code = jsonObj.getString("code");
                    try {
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlFlowGraph cfg = RubyCFGBuilder.build(codeStream);
                            // 打包CFG
                            packCFG(map1, jsonObj, cfg);
                        } catch (Throwable ex) {
                            log.error("ruby文件CFG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes2 = code.getBytes();
                            InputStream codeStream2 = new ByteArrayInputStream(bytes2);
                            DataDependenceGraph ddg = RubyDDGBuilder.build(codeStream2);
                            // 打包DDG
                            packDDG(map3, jsonObj, ddg);
                        } catch (Throwable ex) {
                            log.error("ruby文件DDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlDependenceGraph cdg = RubyCDGBuilder.build(codeStream);
                            // 打包CDG
                            packCDG(map2, jsonObj, cdg);
                        } catch (Throwable ex) {
                            log.error("ruby文件CDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            AbstractSyntaxTree ast = RubyASTBuilder.build(codeStream);
                            // 打包AST
                            packAST(map4, jsonObj, ast);
                        } catch (Throwable ex) {
                            log.error("Ruby文件AST解析异常：" + fileName + "行数：" + lineNum);
                        }
                        bufferedWriter.write(jsonObj.toJSONString());
                        bufferedWriter.newLine();
                        log.error("第" + lineNum + "行处理完毕!");
                    } catch (Throwable ex) {
                        log.error("文件：" + fileName + "行数：" + lineNum);
                    } finally {
                        map1.clear();
                        map2.clear();
                        map3.clear();
                        map4.clear();
                        log.error("文件" + fileName + ":" + formatter.format((double) lineNum / 30000));
                    }
                }

                case "javascript" -> {
                    log.info("You selected JavaScript programming language.");
                    // 执行与JavaScript相关的代码
                    String code = jsonObj.getString("code");
                    try {
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlFlowGraph cfg = JavaScriptCFGBuilder.build(codeStream);
                            // 打包CFG
                            packCFG(map1, jsonObj, cfg);
                        } catch (Throwable ex) {
                            log.error("javascript文件CFG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes2 = code.getBytes();
                            InputStream codeStream2 = new ByteArrayInputStream(bytes2);
                            DataDependenceGraph ddg = JavaScriptDDGBuilder.build(codeStream2);
                            // 打包DDG
                            packDDG(map3, jsonObj, ddg);
                        } catch (Throwable ex) {
                            log.error("javascript文件DDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlDependenceGraph cdg = JavaScriptCDGBuilder.build(codeStream);
                            // 打包CDG
                            packCDG(map2, jsonObj, cdg);
                        } catch (Throwable ex) {
                            log.error("javascript文件CDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            AbstractSyntaxTree ast = JavaScriptASTBuilder.build(codeStream);
                            // 打包AST
                            packAST(map4, jsonObj, ast);
                        } catch (Throwable ex) {
                            log.error("javascript文件AST解析异常：" + fileName + "行数：" + lineNum);
                        }
                        bufferedWriter.write(jsonObj.toJSONString());
                        bufferedWriter.newLine();
                        log.error("第" + lineNum + "行处理完毕!");
                    } catch (Throwable ex) {
                        log.error("文件：" + fileName + "行数：" + lineNum);
                    } finally {
                        map1.clear();
                        map2.clear();
                        map3.clear();
                        map4.clear();
                        log.error("文件" + fileName + ":" + formatter.format((double) lineNum / 30000));
                    }
                }

                case "c++" -> {
                    log.info("You selected C++ programming language.");
                    // 执行与C++相关的代码
                    String code = jsonObj.getString("code");
                    try {
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            ControlFlowGraph cfg = CppCFGBuilder.build(codeStream);
                            // 打包CFG
                            packCFG(map1, jsonObj, cfg);
                        } catch (Throwable ex) {
                            log.error("CPP文件CFG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes2 = code.getBytes();
                            InputStream codeStream2 = new ByteArrayInputStream(bytes2);
                            DataDependenceGraph ddg = CppDDGBuilder.build(codeStream2);
                            // 打包DDG
                            packDDG(map3, jsonObj, ddg);
                        } catch (Throwable ex) {
                            log.error("CPP文件DDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            //                                    ControlDependenceGraph cdg = CppCDGBuilder.build(codeStream);
                            ControlDependenceGraph cdg = null;
                            // 打包CDG
                            packCDG(map2, jsonObj, cdg);
                        } catch (Throwable ex) {
                            log.error("CPP文件CDG解析异常：" + fileName + "行数：" + lineNum);
                        }
                        try {
                            byte[] bytes = code.getBytes();
                            InputStream codeStream = new ByteArrayInputStream(bytes);
                            AbstractSyntaxTree ast = CppASTBuilder.build(codeStream);
                            // 打包AST
                            packAST(map4, jsonObj, ast);
                        } catch (Throwable ex) {
                            log.error("cpp文件AST解析异常：" + fileName + "行数：" + lineNum);
                        }
                        bufferedWriter.write(jsonObj.toJSONString());
                        bufferedWriter.newLine();
                        log.error("第" + lineNum + "行处理完毕!");
                    } catch (Throwable ex) {
                        log.error("文件：" + fileName + "行数：" + lineNum);
                    } finally {
                        map1.clear();
                        map2.clear();
                        map3.clear();
                        map4.clear();
                        log.error("文件" + fileName + ":" + formatter.format((double) lineNum / 30000));
                    }

                    // 写入结果文件
                    synchronized (bufferedWriter) {
                        bufferedWriter.write(jsonObj.toJSONString());
                        bufferedWriter.newLine();
                    }

                    log.info("第" + lineNum + "行处理完毕!");
                }

                // 如果没有匹配的情况，执行默认的代码块
                default -> log.info("Unsupported programming language.");

            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
//        bufferedWriter.flush();
    }


    private void packCDG(Map<String, Set<String>> map2, JSONObject jsonObj, ControlDependenceGraph cdg) {
        Iterator<Edge<PDNode, CDEdge>> it = cdg.allEdgesIterator();
        while (it.hasNext()) {
            Edge<PDNode, CDEdge> edge = it.next();
            wrapToMap(map2, edge.source.getCode(), edge.target.getCode());
        }
        jsonObj.put("control_dependency", map2);
    }

    private void packAST(Map<String, Set<String>> map4, JSONObject jsonObj, AbstractSyntaxTree ast) {
        Iterator<Edge<ASNode, ASEdge>> it = ast.allEdgesIterator();
        while (it.hasNext()) {
            Edge<ASNode, ASEdge> edge = it.next();
            wrapToMap(map4, edge.source, edge.target);
//            wrapToMap(map4, edge.source.getCode(), edge.target.getCode());
        }
        jsonObj.put("AST_Edge", map4);
    }

    private void packDDG(Map<String, Set<String>> map3, JSONObject jsonObj, DataDependenceGraph ddg) {
        Iterator<Edge<PDNode, DDEdge>> it = ddg.allEdgesIterator();
        while (it.hasNext()) {
            Edge<PDNode, DDEdge> edge = it.next();
            wrapToMap(map3, edge.source.getCode(), edge.target.getCode());
        }
        jsonObj.put("data_dependency", map3);
    }

    private void packCFG(Map<String, Set<String>> map1, JSONObject jsonObj, ControlFlowGraph cfg) {
        Iterator<Edge<CFNode, CFEdge>> it = cfg.allEdgesIterator();
        while (it.hasNext()) {
            Edge<CFNode, CFEdge> edge = it.next();
            wrapToMap(map1, edge.source.getCode(), edge.target.getCode());
        }
        jsonObj.put("cfg_dependency", map1);
    }


    private static void wrapToMap(Map<String, Set<String>> map, String code2, String code3) {
        if (map.get(code2) == null) {
            Set<String> set = new HashSet<>();
            set.add(code3);
            map.put(code2, set);
        } else {
            map.get(code2).add(code3);
        }
    }

    // To deal with the AST Node
    private static void wrapToMap(Map<String, Set<String>> map, ASNode srcNode, ASNode tarNode) {
        String srcContent = (srcNode.getCode() == null || srcNode.getCode() == "") ? srcNode.getProperty("type").toString() : srcNode.getCode();
        String tarContent = (tarNode.getCode() == null || tarNode.getCode() == "") ? tarNode.getProperty("type").toString() : tarNode.getCode();
        srcContent = srcNode.getId() + ":" + srcContent;
        tarContent = tarNode.getId() + ":" + tarContent;
        if (map.get(srcContent) == null) {
            Set<String> set = new HashSet<>();
            set.add(tarContent);
            map.put(srcContent, set);
        } else {
            map.get(srcContent).add(tarContent);
        }
    }
}
